﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Diagnostics;

namespace QuickTuner
{
    public partial class radioForm : Form
    {
        // class to help store validity of states across multiple threads that updates the UI
        protected class ValidAsyncState
        {
            public ValidAsyncState() { IsStillValid = true; }
            public bool IsStillValid { get; set; }
        }

        private Radio _radio;                           // the Radio engine

        private List<ToolStripMenuItem> _menuItems;     // List of items for later ref.

        private ValidAsyncState _lastState;             // Track background UI thread validity

        private bool _isDragging;                       // Track form dragging
        private Point _lastMouseLocation;               // Track mouse for form-dragging

        // constructors _________________________________________________________________

        public radioForm(Radio theRadio)
        {
            InitializeComponent();

            this.Icon = QuickTuner.Properties.Resources.AppIcon;
            trayIcon.Icon = QuickTuner.Properties.Resources.AppIcon;


            // attach to the radio engine
            _radio = theRadio;
            _radio.CurrentStationChanged += radio_CurrentStationChanged;
            _radio.PlayStateChanged += radio_PlayStateChnged;

            // bogus state to avoid null checks
            _lastState = new ValidAsyncState();

            // menu items cache
            _menuItems = new List<ToolStripMenuItem>();

            updatePlayState();
            updateCurrentStation();
            updateStationList();
        }

        // UI update routines ___________________________________________________________

        private void updateStationList()
        {
            // remove all cached items
            _menuItems.Map(item => stationsListMenu.Items.Remove(item));

            // rebuild menu items
            _menuItems.AddRange(_radio.Stations.Select(station => {

                var menuItem = new ToolStripMenuItem();
                menuItem.Text = station.Title;

                // download icon in the background
                IconProvider.BeginGetIcon(station, ar => {
                    var img = IconProvider.EndGetIcon(ar);
                    if (img != null) setToolStripImage(menuItem, img);
                });

                menuItem.Tag = station;

                menuItem.Click += stationItem_Click;
                return menuItem;
            }));

            // add them back to the drop down
            // index is required so items are inserted above any existing menus there
            var index = 0;
            _menuItems.Map(item => stationsListMenu.Items.Insert(index++, item));
        }

        private void updateCurrentStation()
        {
            var station = _radio.CurrentStation;

            stationsListDropDown.Text = station.Title;

            // invalid last session
            _lastState.IsStillValid = false;

            // create a new state flag
            _lastState = new ValidAsyncState();

            IconProvider.BeginGetIcon(station, ar => {
                var img = IconProvider.EndGetIcon(ar)
                    ?? QuickTuner.Properties.Resources.music;

                // check if this download operation is still valid
                // if so, we assign the image normally, else we just return.
                if ((ar.AsyncState as ValidAsyncState).IsStillValid)
                    setToolStripImage(stationsListDropDown, img);

            }, _lastState);
        }

        private void updatePlayState()
        {
            if (_radio.IsPlaying) {
                playToggleButton.Image = QuickTuner.Properties.Resources.stop;
                playToggleMenu.Image = QuickTuner.Properties.Resources.stop;

            } else {
                playToggleButton.Image = QuickTuner.Properties.Resources.play;
                playToggleMenu.Image = QuickTuner.Properties.Resources.stop;

            }
        }

        // cross-thread helper
        private void setToolStripImage(ToolStripItem item, Image img)
        {
            if (this.InvokeRequired)
                this.Invoke(new Action<ToolStripItem, Image>(setToolStripImage),
                    item, img);

            else {
                item.Image = img;

            }
        }

        // Event Handlers _______________________________________________________________

        // Radio Events

        private void radio_CurrentStationChanged(object sender, EventArgs e)
        {
            updateCurrentStation();
        }

        private void radio_PlayStateChnged(object sender, EventArgs e)
        {
            updatePlayState();
        }

        // UI Events

        private void stationItem_Click(object sender, EventArgs e)
        {
            var control = (sender as ToolStripMenuItem);

            var station = control.Tag as Station;
            _radio.CurrentStation = station;
        }

        private void quitButton_Click(object sender, EventArgs e)
        {
            _radio.Stop();
            this.Close();
        }

        private void quitButton_MouseEnter(object sender, EventArgs e)
        {
            // change into red image
            var target = (ToolStripItem)sender;
            target.Image = QuickTuner.Properties.Resources.quit;
        }
        private void quitButton_MouseLeave(object sender, EventArgs e)
        {
            // change into grayed image
            var target = (ToolStripItem)sender;
            target.Image = QuickTuner.Properties.Resources.quit_gray;
        }

        private void playToggleButton_Click(object sender, EventArgs e)
        {
            // issue proper play/stop
            if (!_radio.IsPlaying)
                _radio.Play();
            else
                _radio.Stop();

            updatePlayState();
        }

        private void editStationsMenu_Click(object sender, EventArgs e)
        {
            if (!editForm.InstanceRunning)
                new editForm(_radio.Stations).ShowDialog();
        }

        // dragging support

        private void dragHolder_MouseDown(object sender, MouseEventArgs e)
        {
            _lastMouseLocation = e.Location;
            _isDragging = true;
        }
        private void dragHolder_MouseMove(object sender, MouseEventArgs e)
        {
            if (_isDragging)
                calculateDrag(e.Location);
        }
        private void dragHolder_MouseLeave(object sender, EventArgs e)
        {
            if (_isDragging)
                calculateDrag(toolStrip.PointToClient(Control.MousePosition));
        }
        private void dragHolder_MouseUp(object sender, MouseEventArgs e)
        {
            _isDragging = false;
        }

        private void calculateDrag(Point newMouseLocation)
        {
            var dx = newMouseLocation.X - _lastMouseLocation.X;
            var dy = newMouseLocation.Y - _lastMouseLocation.Y;

            this.Location = new Point(
                this.Location.X + dx,
                this.Location.Y + dy);
        }


    }


}
